package com.ccteam.shared.data

import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.ccteam.model.PageDTO
import com.ccteam.model.PageVO
import com.ccteam.network.ApiError
import com.ccteam.network.ApiResult
import com.ccteam.network.ResultVO
import com.ccteam.network.exception.ApiException
import com.orhanobut.logger.Logger

/**
 * @author Xiaoc
 * @since 2021/2/5
 *
 * 封装的基本分页 [PagingSource]
 * 它基于 Paging3 并且基于 FluidMusic 的 [PageDTO] 分页格式
 * 它封装了基本的错误处理与成功后的分页策略，你只需要实现 [loadData] 方法返回从网络端获取的数据信息
 *
 * @param Result 真正分页的数据类型
 **/
abstract class BasePagingSource<Result : Any> : PagingSource<PageDTO, Result>() {

    final override suspend fun load(params: LoadParams<PageDTO>): LoadResult<PageDTO, Result> {
            val nextPageInfo = params.key ?: PageDTO(params.loadSize, 1)

            try {
                when (val result = loadData(nextPageInfo)) {
                    is ApiResult.Success -> {
                        // 如果获取到了数据，则开始准备数据并配置下一页数据内容
                        val data = result.data.data!!
                        // 如果当前页查询到的数量小于我们的分页大小阈值，说明已经没有后面的内容了
                        val nextPage = if (data.records.size >= params.loadSize) {
                            PageDTO(params.loadSize, data.current.plus(1))
                        } else {
                            null
                        }

                        return LoadResult.Page(
                            data.records,
                            null,
                            nextPage
                        )
                    }
                    is ApiResult.Failure -> {
                        // 如果失败则显示具体错误信息
                        return LoadResult.Error(
                            ApiException(result.errorCode, result.errorMsg)
                        )
                    }
                    is ApiResult.Empty -> {
                        return LoadResult.Error(
                            ApiException(ApiError.dataIsNull)
                        )
                    }
                }
            } catch (e: Exception) {
                Logger.d("分页处理出现错误：${e.javaClass.name} - ${e.message}")
                return LoadResult.Error(
                    ApiException(ApiError.unknownError)
                )
            }
    }

    /**
     * 调用Data的API接口，返回对应内容
     */
    abstract suspend fun loadData(pageInfo: PageDTO): ApiResult<ResultVO<PageVO<Result>>>

    override fun getRefreshKey(state: PagingState<PageDTO, Result>): PageDTO? {
        return state.anchorPosition?.let { anchorPosition ->
            val anchorPage = state.closestPageToPosition(anchorPosition)
            anchorPage?.prevKey?.let {
                PageDTO(state.config.pageSize,it.current.minus(1))
            } ?: anchorPage?.nextKey?.let {
                PageDTO(state.config.pageSize,it.current.plus(1))
            }
        }
    }
}